﻿using System;
using Microsoft.ReportingServices.DataProcessing;
using System.Management.Automation;
using System.Security.Principal;


namespace PowerShellDataProcessingExtension
{
    /// <summary>
    /// Represents a query or command that is used when connected to a data source.
    /// </summary>
    /// <remarks>
    /// The IDbCommand interface enables you to implement a Command class, which represents a statement that 
    /// is executed at a data source. For more information about Command classes, see Implementing a Command 
    /// Class for a Data Processing Extension.  An application does not create an instance of the IDbCommand 
    /// interface directly, but creates an instance of a class that implements IDbCommand.  Classes that 
    /// implement IDbCommand must also implement all required members, and typically define additional members 
    /// to add provider-specific functionality.
    /// </remarks>
    class PSDBCommand : IDbCommand
    {
        private PSDBConnectionExtension connection;
        private String commandText;
        private PSDataParameterCollection parameters = new PSDataParameterCollection();
        private PSDBTransaction transaction;

        private PSDataReader reader;

        /// <summary>
        /// Initializes a new instance of the PrvCommand class.
        /// </summary>
        public PSDBCommand(){}
        
        /// <summary>
        /// Initializes a new instance of the PrvCommand class with the text of the query.
        /// </summary>
        /// <param name="connection"></param>
        public PSDBCommand(PSDBConnectionExtension connection)
        {
            this.connection = connection;
        }

        /// <summary>
        /// Initializes a new instance of the PrvCommand class with the text of the query.
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="commandText"></param>
        public PSDBCommand(PSDBConnectionExtension connection, String commandText)
        {
            this.connection = connection;
            this.commandText = commandText;
        }

        /// <summary>
        /// Attempts to cancels the execution of an IDbCommand.
        /// </summary>
        void IDbCommand.Cancel()
        {
            this.reader.powershell.Stop();   
        }

        /// <summary>
        /// Gets or sets the text command to run against the data source.
        /// </summary>
        String IDbCommand.CommandText
        {
            get
            {
                return this.commandText;
            }
            set
            {
                this.commandText = value;
            }
        }

        /// <summary>
        /// Gets or sets the wait time before terminating the attempt to execute a command and generating an error.
        /// </summary>
        int IDbCommand.CommandTimeout
        {
            get
            {
                // we don't support a timeout - this is just a fake getter
                return 30;
            }
            set
            {
                //throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Indicates or specifies how the CommandText property is interpreted (as text, a stored procedure, etc.).
        /// </summary>
        CommandType IDbCommand.CommandType
        {
            /// This DPE only supports CommandType.Text
            get { return CommandType.Text; }
            set { if (value != CommandType.Text) throw new NotSupportedException(); }
        }

        /// <summary>
        /// Creates a new instance of an IDbDataParameter object.
        /// </summary>
        /// <returns></returns>
        IDataParameter IDbCommand.CreateParameter()
        {
            return (IDataParameter)(new PSDataParameter());
        }

        /// <summary>
        /// Executes the CommandText against the Connection and builds an IDataReader
        /// </summary>
        /// <param name="behavior"></param>
        /// <returns></returns>
        IDataReader IDbCommand.ExecuteReader(CommandBehavior behavior)
        {

            WindowsImpersonationContext impersonationContext = null;            
            try
            {
                if (this.connection.ConnectionUser != null)
                {
                    impersonationContext = this.connection.ConnectionUser.Impersonate();
                }

                // Execute the command.      
                this.reader = new PSDataReader();
                this.reader.RunScript(this.commandText, this.parameters);
            }
            finally
            {
                if (impersonationContext != null)
                {
                    impersonationContext.Dispose();
                }
            }

            return this.reader;
        }

        /// <summary>
        /// Gets the IDataParameterCollection
        /// </summary>
        IDataParameterCollection IDbCommand.Parameters
        {
            get { return this.parameters; }
        }

        /// <summary>
        /// Gets or sets the transaction in which the Command object of a Reporting Services data provider executes.
        /// </summary>
        IDbTransaction IDbCommand.Transaction
        {
            get
            {
                return this.transaction;
            }
            set
            {
                 this.transaction = (PSDBTransaction)value;
            }
        }

        void IDisposable.Dispose()
        {
            //TODO - dispose of the object
        }
    }
}
